#ifndef __Pointer_hpp__
#define __Pointer_hpp__

#include "WeakReference.hpp"
#include "Exception.hpp"

namespace ge {

//----------------------------------------------------------------------------//
// AutoPtr< T >
//----------------------------------------------------------------------------//

template < class T >
class AutoPtr
{
 public:

     AutoPtr( void ) : ptr( 0 )
     {
     }

     ~AutoPtr( void )
     {
          if( ptr ) ptr -> Release();
     }

     AutoPtr( const AutoPtr& _ptr ) : ptr( _ptr.Get() )
     {
          if( ptr ) ptr -> AddRef();
     }

     AutoPtr( const T* _ptr ) : ptr( const_cast< T* >( _ptr ) )
     {
          if( ptr ) ptr -> AddRef();
     }

     AutoPtr& operator = ( const AutoPtr& _ptr )
     {
          T* _new_ptr = _ptr.Get();
          if( _new_ptr ) _new_ptr -> AddRef();
          if( ptr ) ptr -> Release();
          ptr = _new_ptr;
          return *this;
     }

     AutoPtr& operator = ( const T* _ptr )
     {
          if( _ptr ) _ptr -> AddRef();
          if( ptr ) ptr -> Release();
          ptr = const_cast< T* >( _ptr );
          return *this;
     }

     T* operator -> ( void ) const
     {
          geDebugAssertT( FailedAccess, ptr != 0, "AutoPtr< T > - No object" );
          return Get();
     }

     T& operator * ( void ) const
     {
          geDebugAssertT( FailedAccess, ptr != 0, "AutoPtr< T > - No object" );
          return *Get();
     }

     operator T* ( void ) const
     {
          return Get();
     }
     /*
     template< class X >
     X* StaticCast( void ) const
     {
          return static_cast< X* >( Get() );
     }

     template< class X >
     X* DynamicCast( void ) const
     {
          return dynamic_cast< X* >( Get() );
     }
     */
     template< class X >
     X* Cast( void ) const
     {
          return dynamic_cast< X* >( Get() );
     }

     T* Get( void ) const
     {
          return const_cast< T* >( ptr );
     }

     WeakReference* GetWeakRef( void ) const
     {
          if( ptr ) return ptr -> GetWeakRef();
          return 0;
     }

 protected:

      T* ptr;
};

//----------------------------------------------------------------------------//
// WeakPtr< T >
//----------------------------------------------------------------------------//

template < class T >
class WeakPtr
{
 public:

     WeakPtr( void ) : ptr( 0 )
     {
     }

     ~WeakPtr( void )
     {
          if( ptr ) ptr -> Release();
     }

     WeakPtr( const WeakPtr& _ptr ) : ptr( _ptr.GetWeakRef() )
     {
          if( ptr ) ptr -> AddRef();
     }

     WeakPtr( const T* _ptr ) : ptr( geChoose( _ptr, _ptr -> GetWeakRef(), 0 ) )
     {
          if( ptr ) ptr -> AddRef();
     }

     WeakPtr& operator = ( const WeakPtr& _ptr )
     {
          WeakReference* _new_ptr = _ptr.GetWeakRef();
          if( _new_ptr ) _new_ptr -> AddRef();
          if( ptr ) ptr -> Release();
          ptr = _new_ptr;
          return *this;
     }

     WeakPtr& operator = ( const T* _ptr )
     {
          WeakReference* _new_ptr = geChoose( _ptr, _ptr -> GetWeakRef(), 0 );
          if( _new_ptr ) _new_ptr -> AddRef();
          if( ptr ) ptr -> Release();
          ptr = _new_ptr;
          return *this;
     }

     T* operator -> ( void ) const
     {
          geDebugAssertT( FailedAccess, ptr != 0 && ptr -> Object() != 0, "WeakPtr< T > - No object" );
          return Get();
     }

     T& operator * ( void ) const
     {
          geDebugAssertT( FailedAccess, ptr != 0 && ptr -> Object() != 0, "WeakPtr< T > - No object" );
          return *Get();
     }

     operator T* ( void ) const
     {
          return Get();
     }
     /*
     template< class X >
     X* StaticCast( void ) const
     {
          return static_cast< X* >( Get() );
     }

     template< class X >
     X* DynamicCast( void ) const
     {
          return dynamic_cast< X* >( Get() );
     }
     */
     template< class X >
     X* Cast( void ) const
     {
          return dynamic_cast< X* >( Get() );
     }

     T* Get( void ) const
     {
          if( ptr ) return dynamic_cast< T* >( ptr -> Object() );
          return 0;
     }

     WeakReference* GetWeakRef( void ) const
     {
          return const_cast< WeakReference* >( ptr );
     }

 protected:

     WeakReference* ptr;
};

//----------------------------------------------------------------------------//
//
//----------------------------------------------------------------------------//

#define GE_DECLARE_PTR( C ) typedef ge::AutoPtr< C > C##Ptr; typedef ge::WeakPtr< C > C##WeakPtr;
#define GE_DECLARE_CLASS( C ) class C; GE_DECLARE_PTR( C );

//----------------------------------------------------------------------------//
//
//----------------------------------------------------------------------------//

} // namespace ge

#endif//__Pointer_hpp__
